package com.hfengxiang.example.canvasrotatedemo;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;

public class RotateProcessor {
    private static final String ROTATE_TAG = "ROTATE_TAG";
    private static final String SCALE_TAG = "SCALE_TAG";
    private static final String ANIMATE_TAG = "ANIMATE_TAG";
    private static final long DURATION = 500;
    private float pointsDownDegree;
    private float targetDegree;
    private float lastDegree;
    private float totalDegree;
    private OnRotateListener rotateListener;
    private float currentSweepDegree;
    private float startDegree;
    private ValueAnimator animator;

    /**
     * 阈值相关
     */
    private float originDownDegree;
    private float overRotateDegree;
    private float startScale;
    private float endScale;
    private final RotateInfo rotateInfo;

    /**
     * 阈值相关
     */
    public RotateProcessor setRotateListener(OnRotateListener rotateListener) {
        this.rotateListener = rotateListener;
        return this;
    }

    public RotateProcessor() {
        rotateInfo = new RotateInfo();
    }

    private float getDegree(MotionEvent event) {
        //两个手指距离x轴分量
        float fingersDownPointDx = event.getX(0) - event.getX(1);
        //两个手指距离y轴分量
        float fingersDownPointDy = event.getY(0) - event.getY(1);
        return (int) Math.round(Math.toDegrees(Math.atan2(fingersDownPointDy, fingersDownPointDx)));
    }


    /**
     * 根据旋转的角度计算出图片复位应当到达的角度
     *
     * @param degree 旋转的角度
     * @return 目标角度
     */
    private int computeTargetDegree(double degree) {
        int[] degrees = {0, 90, 90, 180, 180, 270, 270, 360};
        degree = degree % 360;
        int index = (int) (degree / 45);
        if (index > 0) {
            return degrees[index];
        } else {
            return -1 * degrees[-1 * index];
        }
    }

    public void handleActionDown(MotionEvent event) {
        if (animator != null && animator.isRunning()) {
            return;
        }
        //第二个及之后的手指按下会触发
        if (event.getPointerCount() == 2) {
//            saveRotateCenter(event);
            pointsDownDegree = getDegree(event);
            Log.e("DEBUG", "按下时：pointsDownDegree=" + pointsDownDegree);
            originDownDegree = pointsDownDegree;
            Log.e("DEBUG", "按下时：originDownDegree=" + originDownDegree);
            overRotateDegree = 0;
            lastDegree = 0;
        }
    }

    private void saveRotateCenter(MotionEvent event) {
        float fingersMidPointX = (event.getX(0) + event.getX(1)) / 2;
        float fingersMidPointY = (event.getY(0) + event.getY(1)) / 2;
        rotateInfo.setRotateCenter(fingersMidPointX, fingersMidPointY);
    }

    public void handleActionMove(MotionEvent event) {
        if (animator != null && animator.isRunning()) {
            return;
        }
        if (event.getPointerCount() == 2) {
            float pointsMoveDegree = getDegree(event);
            overRotateDegree = pointsMoveDegree - originDownDegree;
            /**
             * 阈值相关
             */
            if (Math.abs(overRotateDegree) <= 0) {
                Log.i("DEBUG", "移动时：overRotateDegree=" + overRotateDegree);
                pointsDownDegree = pointsMoveDegree;
                return;
            }
            /**
             * 阈值相关
             */
            //TODO 修正角度
            currentSweepDegree = pointsMoveDegree - pointsDownDegree;
            if (lastDegree < 0 && currentSweepDegree > 0) {
                currentSweepDegree = currentSweepDegree - 360;
            }
            if (lastDegree > 0 && currentSweepDegree < 0) {
                currentSweepDegree = currentSweepDegree + 360;
            }
            //TODO 修正角度
            saveRotateCenter(event);
            Log.i("DEBUG", "移动时：currentSweepDegree=" + currentSweepDegree);
            Log.d("DEBUG", "移动时：deltaDegree=" + (currentSweepDegree - lastDegree));
            Log.v("DEBUG", "移动时：totalDegree=" + totalDegree + "+" + (currentSweepDegree - lastDegree));
            float deltaDegree = currentSweepDegree - lastDegree;
            totalDegree = totalDegree + deltaDegree;
            lastDegree = currentSweepDegree;
            if (!rotateInfo.isRotating()) {
                rotateInfo.setRotating(true)
                        .setDeltaDegree(deltaDegree)
                        .setRecovering(false);
                if (rotateListener != null) {
                    rotateListener.onRotateStart(rotateInfo);
                }
            }
            rotateInfo.setCurrentDegree(currentSweepDegree)
                    .setDeltaDegree(deltaDegree)
                    .setTotalDegree(Math.round(totalDegree));
            Log.e(ROTATE_TAG, "扫过的角度：" + currentSweepDegree);
            if (rotateListener != null) {
                rotateListener.onRotate(rotateInfo);
            }
        }
    }

    public void handleActionUp(MotionEvent event) {
        if (animator != null && animator.isRunning()) {
            return;
        }
        if (event.getPointerCount() == 2 && event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
            recover();
        }
    }

    private void recover() {
        //保存手指松开时两指连线已经扫过的角度
        targetDegree = computeTargetDegree(currentSweepDegree);
        Log.v(ROTATE_TAG, "抬起时，应当转到的角度：" + targetDegree);
        startDegree = currentSweepDegree % 360;
        Log.i(ANIMATE_TAG, "抬起时扫过的夹角：" + startDegree + ",目标夹角：" + targetDegree);
        if (rotateListener != null) {
            float[] scale = rotateListener.onCalculateScale(totalDegree);
            startScale = scale[0];
            endScale = scale[1];
        }
        startAnimator();
    }

    private void startAnimator() {
        if (animator == null) {
            animator = ObjectAnimator.ofFloat(50f, 100f);
            float fraction = Math.abs((targetDegree - startDegree)) / 45f;
            animator.setDuration((long) (DURATION * fraction));
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float fraction = animation.getAnimatedFraction();
                    float value = (float) animation.getAnimatedValue();
                    Log.i("onAnimationUpdate", "fraction" + fraction + ",value=" + value);
                    float deltaDegree = (targetDegree - startDegree) * fraction;
                    currentSweepDegree = startDegree + deltaDegree;
                    float delta = currentSweepDegree - lastDegree;
                    totalDegree = totalDegree + delta;
                    lastDegree = currentSweepDegree;

                    float deltaScale = (endScale - startScale) * fraction;

                    Log.i(ANIMATE_TAG, "startDegree=" + startDegree);
                    Log.d(ANIMATE_TAG, "deltaDegree=" + deltaDegree);
                    Log.v(ANIMATE_TAG, "currentSweepDegree=" + currentSweepDegree);
                    if (fraction == 1.0) {
                        totalDegree = Math.round(totalDegree);
                        Log.v("over", "动画结束了");
                        rotateInfo.reset();
                        if (rotateListener != null) {
                            rotateInfo.setRotating(false)
                                    .setRecovering(false)
                                    .setDeltaDegree(delta)
                                    .setCurrentDegree(currentSweepDegree)
                                    .setTotalDegree(Math.abs(totalDegree))
                                    .setProgress(fraction)
                                    .setScale(startScale + deltaScale);
                            rotateListener.onRotateEnd(rotateInfo);
                        }
                    }
                    if (rotateListener != null) {
                        rotateListener.onRotate(rotateInfo);
                        if (!rotateInfo.isRecovering()) {
                            rotateListener.onRecoverStart(rotateInfo);
                            rotateInfo.setRecovering(true);
                        } else {
                            rotateInfo.setCurrentDegree(currentSweepDegree)
                                    .setTotalDegree(Math.abs(totalDegree))
                                    .setProgress(fraction)
                                    .setScale(startScale + deltaScale);
                            rotateListener.onRotate(rotateInfo);
                        }
                    }
                }
            });
        }
        if (animator.isRunning()) return;
        animator.start();
    }

    interface OnRotateListener {
        void onRotate(RotateInfo info);

        void onRotateStart(RotateInfo rotateInfo);

        void onRecoverStart(RotateInfo info);

        void onRotateEnd(RotateInfo rotateInfo);

        float[] onCalculateScale(float targetDegree);
    }
}
